Conversation
created only by prisma client extension
* reorganized agent code into multiple distinct files * cleaned up some prompt details
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
|
Warning Review limit reached
Next review available in: 36 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR restructures issue status semantics (replacing ACTIVE/FALSE_POSITIVE/REMEDIATED with AFFECTED/NOT_AFFECTED/FIXED/UNDER_INVESTIGATION), makes Issue asset scoping optional in favor of device-group scoping, adds Note/EntityFilter models, and introduces a new VEX sorting agent that determines issue statuses from inbox notifications and writes deterministic updates/overrides. ChangesSchema, migration, and status consumers
Estimated code review effort: 4 (Complex) | ~75 minutes VEX Sorting Agent for Inbox Notifications
Estimated code review effort: 4 (Complex) | ~70 minutes Sequence Diagram(s)sequenceDiagram
participant Inngest as processInboxEmail
participant Context as gatherVexContext
participant Agent as sortVulnerabilities (Claude)
participant Planner as planVexWrites
participant DB as Prisma / Database
Inngest->>Context: gatherVexContext(notificationId)
Context->>DB: fetch notification, vulnerabilities, matchings, notes
DB-->>Context: notification data
Context-->>Inngest: VexContext (markdown, issues)
Inngest->>Agent: sortVulnerabilities(context)
Agent->>Agent: invoke Claude with tool binding
Agent-->>Inngest: VexResult
Inngest->>Planner: planVexWrites(context, result)
Planner-->>Inngest: issueUpdates, assetOverrides
Inngest->>DB: applyVexDeterminations ($transaction)
DB-->>Inngest: VexApplySummary
Inngest-->>Inngest: return { vexSummary }
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
src/features/advisories/server/routers.ts (1)
78-84: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
progressPercentnow countsUNDER_INVESTIGATIONas resolved.
status !== IssueStatus.AFFECTEDtreatsUNDER_INVESTIGATION(a non-terminal, unresolved state) as progress, inflating the percentage. The previous logic excluded only the "active" state and counted genuinely resolved issues. Prefer an explicit allowlist of terminal states.🐛 Proposed fix
- const nonActiveCount = allIssues.filter( - (i) => i.status !== IssueStatus.AFFECTED, - ).length; + const RESOLVED_STATUSES = [ + IssueStatus.FIXED, + IssueStatus.NOT_AFFECTED, + ] as const; + const nonActiveCount = allIssues.filter((i) => + RESOLVED_STATUSES.includes(i.status), + ).length;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/advisories/server/routers.ts` around lines 78 - 84, `progressPercent` is currently inflated because the `nonActiveCount` filter in the advisories router treats `UNDER_INVESTIGATION` as resolved; update the logic to use an explicit allowlist of terminal/resolved statuses instead of checking `status !== IssueStatus.AFFECTED`. Locate the calculation in the advisories server router and adjust the `allIssues.filter(...)` predicate so only genuinely completed states contribute to `progressPercent`.src/features/issues/components/issue.tsx (1)
106-106: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winAvoid deriving the asset link from
issues[0]. Insrc/features/issues/components/issue.tsx:106, 209, 225,type="assets"lists can mix asset-scoped and device-group-scoped issues; if the first item has noassetId, the overflow and “Non-Active Issues” sections disappear even when later items have one. Pick a non-null asset-scoped id from the list, or derive these links from the current asset context.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/issues/components/issue.tsx` at line 106, The asset link is currently derived from issues[0], which can be null for mixed asset/device-group issue lists and breaks the overflow and “Non-Active Issues” sections. Update the issue component logic around the assetId derivation and the related link builders in issue.tsx to use a non-null asset-scoped id from the list, or fall back to the current asset context instead of assuming the first item has an assetId.src/features/advisories/components/advisories.tsx (1)
195-209: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winRename the gray bucket or split out
UNDER_INVESTIGATIONsrc/features/advisories/components/advisories.tsx:195-209
activeis the catch-all remainder, so it includes bothAFFECTEDandUNDER_INVESTIGATIONwhile being labeled "Active". If this chart is meant to show status breakdown, giveUNDER_INVESTIGATIONits own bucket; otherwise rename the label to something like "Open" or "Remaining".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/advisories/components/advisories.tsx` around lines 195 - 209, The gray “Active” bucket in advisories.tsx is a catch-all remainder, so it mixes AFFECTED and UNDER_INVESTIGATION under one label. Update the status breakdown logic around the remediated/falsePos/active calculations to either split UNDER_INVESTIGATION into its own count and legend item, or rename the existing active bucket and label to something like Open/Remaining so the chart matches the actual statuses represented.src/features/assets/components/asset.tsx (1)
208-235: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winFragile positional coupling between enum order and results array.
The tab count/order correctness depends entirely on the literal array
[naResult, aResult, rResult, uiResult]matchingObject.values(IssueStatus)runtime order. The comment documents this, but it's a silent-breakage trap: ifIssueStatusinschema.prismais ever reordered (e.g., alphabetized, or a new status inserted in the middle), tab labels, per-tab items, and pagination keys will silently mismatch with no compile-time or runtime error — only a UI bug caught by a human noticing wrong data under a tab.Consider keying results by status value in a
Record<IssueStatus, ...>instead of relying on array position, which removes the ordering dependency entirely:♻️ Suggested refactor using a status-keyed map
- const naResult = useSuspenseIssuesByAssetId({ - assetId, - issueStatus: IssueStatus.NOT_AFFECTED, - }); - const aResult = useSuspenseIssuesByAssetId({ - assetId, - issueStatus: IssueStatus.AFFECTED, - }); - const rResult = useSuspenseIssuesByAssetId({ - assetId, - issueStatus: IssueStatus.FIXED, - }); - const uiResult = useSuspenseIssuesByAssetId({ - assetId, - issueStatus: IssueStatus.UNDER_INVESTIGATION, - }); - - // Order must match Object.values(IssueStatus) (NOT_AFFECTED, AFFECTED, - // FIXED, UNDER_INVESTIGATION) since results are indexed positionally below. - const results: PaginatedResponse<{ vulnerability: Vulnerability } & Issue>[] = - []; - let showTabs = false; - for (const res of [naResult, aResult, rResult, uiResult]) { - results.push(res.data); - if (res.data.totalCount > 0) { - showTabs = true; - } - } + const resultsByStatus = Object.fromEntries( + Object.values(IssueStatus).map((status) => [ + status, + useSuspenseIssuesByAssetId({ assetId, issueStatus: status }), + ]), + ) as Record<IssueStatus, ReturnType<typeof useSuspenseIssuesByAssetId>>; + + const showTabs = Object.values(resultsByStatus).some( + (res) => res.data.totalCount > 0, + );Note: calling hooks inside
.mapviolates the rules of hooks, so this specific transform isn't directly valid — the safer fix is to keep the four explicit hook calls but assemble the lookup structure afterward, e.g.const resultsByStatus = { [IssueStatus.NOT_AFFECTED]: naResult, ... }, then referenceresultsByStatus[status]in the render loops below instead ofresults[i].🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/assets/components/asset.tsx` around lines 208 - 235, The asset tabs logic in asset.tsx relies on fragile positional matching between the explicit issue queries (naResult, aResult, rResult, uiResult) and the runtime order of IssueStatus. Keep the four useSuspenseIssuesByAssetId calls, but replace the positional results array with a status-keyed lookup such as a Record<IssueStatus, PaginatedResponse<{ vulnerability: Vulnerability } & Issue>> built from those results. Update the tab/rendering code that currently indexes into results to read from that lookup by IssueStatus so ordering changes in IssueStatus cannot silently break tab data.
🧹 Nitpick comments (9)
src/features/inbox/agent/vex/process_output.ts (1)
104-141: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winInteractive transaction with sequential round trips may hit the default timeout.
Each
issueUpdates/assetOverridesentry is a separate awaited round trip inside a single interactive$transaction. With many baseline issues per notification this can exceed Prisma's default interactive-transaction timeout (~5s), aborting the whole batch. Consider raisingtimeout(andmaxWait) on the transaction, or batching writes.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/inbox/agent/vex/process_output.ts` around lines 104 - 141, The interactive Prisma transaction in process_output.ts can time out because issueUpdates and assetOverrides are applied one-by-one with awaited round trips inside prisma.$transaction. Update the transaction in the VEX output handling path to either set a higher timeout/maxWait on prisma.$transaction or batch the writes so the sequential updates in the issueUpdates and assetOverrides loops do not exceed the default interactive-transaction limit.src/features/inbox/agent/vex/index.ts (1)
42-46: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider logging silent failure paths.
Both
if (!call) return {}and thesafeParsefailure branch silently return an empty result, so a missing/malformed tool call produces zero writes with no signal. Since this agent drives DB determinations, aconsole.warn(includingparsed.error) would aid debugging without changing behavior.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/inbox/agent/vex/index.ts` around lines 42 - 46, The Vex tool result parsing in the agent flow is silently swallowing two failure paths: missing tool call and schema parse failure. Update the logic around the TOOL_NAME lookup and schema.safeParse in the Vex index handler to emit a console.warn when no call is found and when parsing fails, including parsed.error for the malformed payload case, while still returning an empty result to preserve behavior.prisma/schema.prisma (2)
689-711: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚖️ Poor tradeoff
EntityFilter"exactly one of noteId/issueId" invariant is unenforced.Line 699 documents the invariant, but nothing prevents both (or neither) being set. Since Prisma can't express XOR constraints, add a raw
CHECKin the migration (e.g.num_nonnulls("noteId","issueId") = 1) or enforce it in the write path so filters can't be silently orphaned or double-owned.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@prisma/schema.prisma` around lines 689 - 711, The EntityFilter model documents an XOR ownership rule for noteId and issueId, but Prisma schema alone does not enforce it. Add enforcement in the EntityFilter write path or the database migration so only one of noteId/issueId can be set at a time and neither/both are rejected; use the EntityFilter model and its create/update flows as the places to apply the validation, and add a raw CHECK constraint in the migration if you want database-level protection.
623-653: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚖️ Poor tradeoff
Issueallows bothassetIdanddeviceGroupMatchingIdto be null.With both scoping identifiers optional and Postgres treating NULLs as distinct in unique constraints, a row can be created with neither set (orphan issue that neither unique constraint binds). The baseline extension always sets
deviceGroupMatchingIdand the VEX override setsassetId, so this is only reachable via a bad write, but the schema does not encode the "exactly one scope" invariant. Consider a DBCHECK ((assetId IS NOT NULL) OR (deviceGroupMatchingId IS NOT NULL))(via raw SQL in the migration) or documenting/validating it at the app layer.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@prisma/schema.prisma` around lines 623 - 653, The Issue model currently allows both assetId and deviceGroupMatchingId to be null, so the schema does not enforce the intended scope invariant. Update the Prisma schema and migration path around Issue to prevent orphan rows by enforcing that at least one scope is present, ideally via a database CHECK constraint added in the migration for the Issue table. If you prefer app-level enforcement, also add validation where Issue records are created or updated, using the Issue model fields assetId and deviceGroupMatchingId to reject writes that leave both unset.prisma/migrations/20260701212209_issue_and_notes/migration.sql (1)
127-151: 🧹 Nitpick | 🔵 TrivialConsider lock-safe DDL for production rollout.
On a large/live DB this migration takes blocking locks: the enum type rewrites (Lines 25-32, 46-53) hold
ACCESS EXCLUSIVE, theCREATE UNIQUE INDEX/CREATE INDEXblock writes, and the added FKs takeSHARE ROW EXCLUSIVEwith a full validating scan. For zero/low-downtime deploys, preferCREATE INDEX CONCURRENTLYand add FKs asNOT VALIDfollowed by a separateVALIDATE CONSTRAINT. If these tables are small or a maintenance window is used, this is fine as-is.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@prisma/migrations/20260701212209_issue_and_notes/migration.sql` around lines 127 - 151, The migration block creating indexes and foreign keys on issue, note, entity_filter, and entity_filter_match can take blocking locks during rollout. Update the CREATE INDEX / CREATE UNIQUE INDEX statements in this migration to use lock-safe concurrent creation where supported, and add the foreign keys with NOT VALID then validate them in a separate step. Use the existing constraint and index names such as issue_deviceGroupMatchingId_vulnerabilityId_key, issue_deviceGroupMatchingId_fkey, note_userId_fkey, entity_filter_noteId_fkey, entity_filter_issueId_fkey, and entity_filter_match_entityFilterId_fkey to keep the changes localized.Source: Linters/SAST tools
src/features/vulnerabilities/components/prioritized-columns.tsx (1)
119-120: 📐 Maintainability & Code Quality | 🔵 TrivialTODO left in code regarding backend display behavior for device-group issues.
Would you like me to help scope this backend change (one issue-per-asset display for device-group issues) or open a tracking issue for it?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/vulnerabilities/components/prioritized-columns.tsx` around lines 119 - 120, Remove the lingering TODO in prioritized-columns.tsx and either implement or explicitly defer the device-group issue display behavior in the relevant component logic, likely around the prioritized columns rendering and issue mapping. If this behavior is not being changed now, replace the comment with a short actionable note that points to the backend/display follow-up, using the existing feature/component context in prioritized-columns.tsx to keep the intent clear.src/lib/string-utils.ts (1)
83-93: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMinor inconsistent empty-value fallback text in
deviceIdentityInline.When
fields.cpeis an array, an empty array renders as"(none)"; whenfields.cpeis a nullish scalar, it renders as"?". Both represent "no CPE known" but use different placeholder text, which could look inconsistent across rendered device identity lines.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/string-utils.ts` around lines 83 - 93, The `deviceIdentityInline` helper uses inconsistent placeholders for missing `cpe` values, showing “(none)” for an empty array but “?” for nullish scalar input. Update the `deviceIdentityInline` logic to use a single fallback string for all empty or missing `cpe` cases so the rendered identity text is consistent across array and scalar inputs.src/features/chat/viper-agent/tools/get-recommendations-context.ts (1)
33-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRaw string literal "AFFECTED" instead of
IssueStatus.AFFECTEDenum.Elsewhere in this cohort (asset.tsx, dashboard-columns.tsx, assets/server/routers.ts) status comparisons use the
IssueStatusenum constant for type safety and to avoid typo risk. Here the comparison uses a raw string literal. IfAssetForContext.issues[].statusis typed asIssueStatus, importing and usingIssueStatus.AFFECTEDwould be more consistent and typo-safe.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/chat/viper-agent/tools/get-recommendations-context.ts` around lines 33 - 35, The status check in get-recommendations-context should use the IssueStatus enum instead of a raw string literal. Update the filter inside the active count logic to compare against IssueStatus.AFFECTED, and import IssueStatus in this module so the comparison stays type-safe and consistent with asset.tsx, dashboard-columns.tsx, and assets/server/routers.ts.src/features/assets/components/asset.tsx (1)
266-266: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winStale fallback text "No Active Issues".
With four statuses now shown (including
NOT_AFFECTEDandUNDER_INVESTIGATION), the empty-state message "No Active Issues" is misleading since it implies only the AFFECTED/active category was checked.💬 Suggested copy fix
- <p className="flex justify-center pt-24">No Active Issues</p> + <p className="flex justify-center pt-24">No Issues found</p>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/assets/components/asset.tsx` at line 266, Update the empty-state copy in the asset view so it no longer says “No Active Issues,” since the status list now includes more than just active/affected items. Adjust the fallback message in the asset component (the JSX around the status/empty-state render in asset.tsx) to a neutral, broader message that matches the four-status view and does not imply only one category was checked.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/features/notes/server/get-relevant-notes.ts`:
- Around line 90-105: The asset note lookup path is doing an N+1 query by
calling getNotesForAsset once per scope.assetIds entry inside getRelevantNotes.
Replace the Promise.all(map(getNotesForAsset)) pattern with a single batched
lookup using getNotesForInstance("ASSET", assetIds) for all asset IDs at once,
then flatten/group results as needed. Keep the existing behavior for persistent,
vulnerabilities, remediations, and matchings unchanged, and only touch the asset
branch in getRelevantNotes/getNotesForAsset.
---
Outside diff comments:
In `@src/features/advisories/components/advisories.tsx`:
- Around line 195-209: The gray “Active” bucket in advisories.tsx is a catch-all
remainder, so it mixes AFFECTED and UNDER_INVESTIGATION under one label. Update
the status breakdown logic around the remediated/falsePos/active calculations to
either split UNDER_INVESTIGATION into its own count and legend item, or rename
the existing active bucket and label to something like Open/Remaining so the
chart matches the actual statuses represented.
In `@src/features/advisories/server/routers.ts`:
- Around line 78-84: `progressPercent` is currently inflated because the
`nonActiveCount` filter in the advisories router treats `UNDER_INVESTIGATION` as
resolved; update the logic to use an explicit allowlist of terminal/resolved
statuses instead of checking `status !== IssueStatus.AFFECTED`. Locate the
calculation in the advisories server router and adjust the
`allIssues.filter(...)` predicate so only genuinely completed states contribute
to `progressPercent`.
In `@src/features/assets/components/asset.tsx`:
- Around line 208-235: The asset tabs logic in asset.tsx relies on fragile
positional matching between the explicit issue queries (naResult, aResult,
rResult, uiResult) and the runtime order of IssueStatus. Keep the four
useSuspenseIssuesByAssetId calls, but replace the positional results array with
a status-keyed lookup such as a Record<IssueStatus, PaginatedResponse<{
vulnerability: Vulnerability } & Issue>> built from those results. Update the
tab/rendering code that currently indexes into results to read from that lookup
by IssueStatus so ordering changes in IssueStatus cannot silently break tab
data.
In `@src/features/issues/components/issue.tsx`:
- Line 106: The asset link is currently derived from issues[0], which can be
null for mixed asset/device-group issue lists and breaks the overflow and
“Non-Active Issues” sections. Update the issue component logic around the
assetId derivation and the related link builders in issue.tsx to use a non-null
asset-scoped id from the list, or fall back to the current asset context instead
of assuming the first item has an assetId.
---
Nitpick comments:
In `@prisma/migrations/20260701212209_issue_and_notes/migration.sql`:
- Around line 127-151: The migration block creating indexes and foreign keys on
issue, note, entity_filter, and entity_filter_match can take blocking locks
during rollout. Update the CREATE INDEX / CREATE UNIQUE INDEX statements in this
migration to use lock-safe concurrent creation where supported, and add the
foreign keys with NOT VALID then validate them in a separate step. Use the
existing constraint and index names such as
issue_deviceGroupMatchingId_vulnerabilityId_key,
issue_deviceGroupMatchingId_fkey, note_userId_fkey, entity_filter_noteId_fkey,
entity_filter_issueId_fkey, and entity_filter_match_entityFilterId_fkey to keep
the changes localized.
In `@prisma/schema.prisma`:
- Around line 689-711: The EntityFilter model documents an XOR ownership rule
for noteId and issueId, but Prisma schema alone does not enforce it. Add
enforcement in the EntityFilter write path or the database migration so only one
of noteId/issueId can be set at a time and neither/both are rejected; use the
EntityFilter model and its create/update flows as the places to apply the
validation, and add a raw CHECK constraint in the migration if you want
database-level protection.
- Around line 623-653: The Issue model currently allows both assetId and
deviceGroupMatchingId to be null, so the schema does not enforce the intended
scope invariant. Update the Prisma schema and migration path around Issue to
prevent orphan rows by enforcing that at least one scope is present, ideally via
a database CHECK constraint added in the migration for the Issue table. If you
prefer app-level enforcement, also add validation where Issue records are
created or updated, using the Issue model fields assetId and
deviceGroupMatchingId to reject writes that leave both unset.
In `@src/features/assets/components/asset.tsx`:
- Line 266: Update the empty-state copy in the asset view so it no longer says
“No Active Issues,” since the status list now includes more than just
active/affected items. Adjust the fallback message in the asset component (the
JSX around the status/empty-state render in asset.tsx) to a neutral, broader
message that matches the four-status view and does not imply only one category
was checked.
In `@src/features/chat/viper-agent/tools/get-recommendations-context.ts`:
- Around line 33-35: The status check in get-recommendations-context should use
the IssueStatus enum instead of a raw string literal. Update the filter inside
the active count logic to compare against IssueStatus.AFFECTED, and import
IssueStatus in this module so the comparison stays type-safe and consistent with
asset.tsx, dashboard-columns.tsx, and assets/server/routers.ts.
In `@src/features/inbox/agent/vex/index.ts`:
- Around line 42-46: The Vex tool result parsing in the agent flow is silently
swallowing two failure paths: missing tool call and schema parse failure. Update
the logic around the TOOL_NAME lookup and schema.safeParse in the Vex index
handler to emit a console.warn when no call is found and when parsing fails,
including parsed.error for the malformed payload case, while still returning an
empty result to preserve behavior.
In `@src/features/inbox/agent/vex/process_output.ts`:
- Around line 104-141: The interactive Prisma transaction in process_output.ts
can time out because issueUpdates and assetOverrides are applied one-by-one with
awaited round trips inside prisma.$transaction. Update the transaction in the
VEX output handling path to either set a higher timeout/maxWait on
prisma.$transaction or batch the writes so the sequential updates in the
issueUpdates and assetOverrides loops do not exceed the default
interactive-transaction limit.
In `@src/features/vulnerabilities/components/prioritized-columns.tsx`:
- Around line 119-120: Remove the lingering TODO in prioritized-columns.tsx and
either implement or explicitly defer the device-group issue display behavior in
the relevant component logic, likely around the prioritized columns rendering
and issue mapping. If this behavior is not being changed now, replace the
comment with a short actionable note that points to the backend/display
follow-up, using the existing feature/component context in
prioritized-columns.tsx to keep the intent clear.
In `@src/lib/string-utils.ts`:
- Around line 83-93: The `deviceIdentityInline` helper uses inconsistent
placeholders for missing `cpe` values, showing “(none)” for an empty array but
“?” for nullish scalar input. Update the `deviceIdentityInline` logic to use a
single fallback string for all empty or missing `cpe` cases so the rendered
identity text is consistent across array and scalar inputs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: df3f8d55-9f83-41e2-b451-3236219dcdbb
📒 Files selected for processing (31)
prisma/migrations/20260701212209_issue_and_notes/migration.sqlprisma/schema.prismaprisma/seed.tsscripts/seed-icsma-24-319-01.tsscripts/seed-notifications.tssrc/app/api/v1/__tests__/vulnerabilities.test.tssrc/components/status-form.tsxsrc/features/advisories/components/advisories.tsxsrc/features/advisories/server/routers.tssrc/features/advisories/types.tssrc/features/assets/components/asset.tsxsrc/features/assets/components/dashboard-columns.tsxsrc/features/assets/params.tssrc/features/assets/server/routers.tssrc/features/chat/utils.tssrc/features/chat/viper-agent/tools/get-recommendations-context.tssrc/features/inbox/agent/vex/__tests__/vex.test.tssrc/features/inbox/agent/vex/context.tssrc/features/inbox/agent/vex/index.tssrc/features/inbox/agent/vex/process_output.tssrc/features/inbox/agent/vex/tools.tssrc/features/issues/components/issue.tsxsrc/features/issues/hooks/use-issues.tssrc/features/notes/server/get-relevant-notes.tssrc/features/tracking/types.tssrc/features/vulnerabilities/components/prioritized-columns.tsxsrc/inngest/functions/process-inbox-email.tssrc/lib/prisma-client-extensions.tssrc/lib/string-utils.tssrc/test/server-only-stub.tsvitest.config.mts
There was a problem hiding this comment.
There was a problem hiding this comment.
I tested on this scenario: https://www.siemens-healthineers.com/support-documentation/cybersecurity/ssa-016040
I added notes to suggest that one issue should be created to be NOT_AFFECTED, and confirmed that this was the case in an end-to-end test
There was a problem hiding this comment.
tests the deterministic writes that should run based on the output of the VEX agent
There was a problem hiding this comment.
Agent gets:
- Markdown for all linked vulnerabilities
- Markdown for all linked remediations
- Markdown for all linked device groups
- The number of assets that are in each linked device group
- All notes that are linked to any of the above (created TODO helper fn for this)
- Persistent notes that always affect the hospital
There was a problem hiding this comment.
I'd look at tools.ts first to see what the agent output is
We process that output to create/modify issues as necessary
There was a problem hiding this comment.
helper fn to match notes to VIPER db objects. some functionality in CDST RFC unimplemented for now (see VW-358)
There was a problem hiding this comment.
On vulnerability create, create one issue per DeviceGroupMatching
Issuemodel per CDST IV&V RFC -- now include VEX status fields, asset-level issues override device-group-matching-level issuesNotemodel andEntityFiltermodels per CDST IV&V RFC -- notes are more structured ways of storing information about an asset/vulns/remediation, etcvexagent sorts vulnerabilities into UNDER_INVESTIGATION, AFFECTED, NOT_AFFECTEDSummary by CodeRabbit
New Features
Bug Fixes